source('../settings/settings.R')
source('commonFunctions.R')
set.seed(43)
drive1 <- read.csv('../data/processed/analysis/TT1_Drive_1_PP.csv')
drive2 <- read.csv('../data/processed/Analysis/TT1_Drive_2_PP.csv')
drive3 <- read.csv('../data/processed/Analysis/TT1_Drive_3_PP.csv')
drive4 <- read.csv('../data/processed/Analysis/TT1_Drive_4_PP.csv', stringsAsFactors = T)
dfSeg <- data.frame(rep(1, nrow(drive4)), rep(2, nrow(drive4)), rep(3, nrow(drive4)), rep(4, nrow(drive4)))
names(dfSeg) <- c("Seg1", "Seg2", "Seg3", "Seg4")

combinedDf_Seg1 <- cbind(drive4, 
                    drive1$MeanPP_Seg0, 
                    drive2$MeanPP_Seg1, drive3$MeanPP_Seg1, 
                    drive2$MeanPP_Seg0_1, drive3$MeanPP_Seg0_1,
                    drive2$StdPP_Seg1, drive3$StdPP_Seg1,
                    drive2$StdPP_Seg0_1, drive3$StdPP_Seg0_1,
                    dfSeg$Seg1
                  )
combinedDf_Seg2 <- cbind(drive4, 
                    drive1$MeanPP_Seg0, 
                    drive2$MeanPP_Seg2, drive3$MeanPP_Seg2, 
                    drive2$MeanPP_Seg0_2, drive3$MeanPP_Seg0_2,
                    drive2$StdPP_Seg2, drive3$StdPP_Seg2,
                    drive2$StdPP_Seg0_2, drive3$StdPP_Seg0_2,
                    dfSeg$Seg2
                  )
combinedDf_Seg3 <- cbind(drive4, 
                    drive1$MeanPP_Seg0, 
                    drive2$MeanPP_Seg3, drive3$MeanPP_Seg3, 
                    drive2$MeanPP_Seg0_3, drive3$MeanPP_Seg0_3,
                    drive2$StdPP_Seg3, drive3$StdPP_Seg3,
                    drive2$StdPP_Seg0_3, drive3$StdPP_Seg0_3,
                    dfSeg$Seg3
                  )
combinedDf_Seg4 <- cbind(drive4, 
                    drive1$MeanPP_Seg0, 
                    drive2$MeanPP_Seg4, drive3$MeanPP_Seg4, 
                    drive2$MeanPP_Seg0_4, drive3$MeanPP_Seg0_4,
                    drive2$StdPP_Seg4, drive3$StdPP_Seg4,
                    drive2$StdPP_Seg0_4, drive3$StdPP_Seg0_4,
                    dfSeg$Seg4
                  )

names(combinedDf_Seg1) <- c(names(drive4), 
                       "PP_Dev_1_Turning",
                       "PP_Dev_2_Straight", "PP_Dev_3_Straight", 
                       "PP_Dev_2_Turning", "PP_Dev_3_Turning", 
                       "Std_PP_2_Straight", "Std_PP_3_Straight", 
                       "Std_PP_2_Turning", "Std_PP_3_Turning", 
                       "Segment")
names(combinedDf_Seg2) <- c(names(drive4), 
                       "PP_Dev_1_Turning",
                       "PP_Dev_2_Straight", "PP_Dev_3_Straight", 
                       "PP_Dev_2_Turning", "PP_Dev_3_Turning", 
                       "Std_PP_2_Straight", "Std_PP_3_Straight", 
                       "Std_PP_2_Turning", "Std_PP_3_Turning", 
                       "Segment")
names(combinedDf_Seg3) <- c(names(drive4), 
                       "PP_Dev_1_Turning",
                       "PP_Dev_2_Straight", "PP_Dev_3_Straight", 
                       "PP_Dev_2_Turning", "PP_Dev_3_Turning", 
                       "Std_PP_2_Straight", "Std_PP_3_Straight", 
                       "Std_PP_2_Turning", "Std_PP_3_Turning", 
                       "Segment")
names(combinedDf_Seg4) <- c(names(drive4), 
                       "PP_Dev_1_Turning",
                       "PP_Dev_2_Straight", "PP_Dev_3_Straight", 
                       "PP_Dev_2_Turning", "PP_Dev_3_Turning", 
                       "Std_PP_2_Straight", "Std_PP_3_Straight", 
                       "Std_PP_2_Turning", "Std_PP_3_Turning", 
                       "Segment")

# combinedDf_Seg1$Subject <- paste0(as.factor(combinedDf_Seg1$Subject), ".S1")
# combinedDf_Seg2$Subject <- paste0(as.factor(combinedDf_Seg2$Subject), ".S2")
# combinedDf_Seg3$Subject <- paste0(as.factor(combinedDf_Seg3$Subject), ".S3")
# combinedDf_Seg4$Subject <- paste0(as.factor(combinedDf_Seg4$Subject), ".S4")

combinedDf <- rbind(combinedDf_Seg1, combinedDf_Seg2, combinedDf_Seg3, combinedDf_Seg4)

combinedDf$Subject <- paste0("#", str_pad(combinedDf$Subject, 2, pad="0"))
combinedDf$Segment <- as.factor(combinedDf$Segment)
combinedDf_NoStressor <- combinedDf[combinedDf$Activity == "NO",]
combinedDf_Cognitive <- combinedDf[combinedDf$Activity == "C",]
combinedDf_Motoric <- combinedDf[combinedDf$Activity == "M",]

# combinedDf_NoStressor$Subject <- as.factor(combinedDf_NoStressor$Subject)
# combinedDf_Cognitive$Subject <- as.factor(combinedDf_Cognitive$Subject)
# combinedDf_Motoric$Subject <- as.factor(combinedDf_Motoric$Subject)
COLOR_NORMAL <- list(color='rgb(120,120,120)')
COLOR_COGNITIVE <- list(color='rgb(158,202,225)')
COLOR_MOTORIC <- list(color='rgb(58,200,225)')
COLOR_FAILURE <- list(color='red')

THRESHOLD_MILD = 0.07
THRESHOLD_EXTREME = 0.2

MARKER_LINE_MILD = list(color="blue")
MARKER_LINE_EXTREME = list(color="red")
library(nlme)
combinedDf$Subject = as.factor(combinedDf$Subject)
combinedDf$Activity = as.factor(combinedDf$Activity)
combinedDf$PP_Dev_Group = ifelse(combinedDf$PP_Dev > THRESHOLD_MILD, 1, 0)
model = lm(PP_Dev ~ 
              abs(PP_Dev_2_Straight) + 
              abs(PP_Dev_3_Straight) +
              abs(PP_Dev_2_Turning) + 
              abs(PP_Dev_3_Turning) + 
              Std_PP_2_Straight + 
              Std_PP_3_Straight + 
              Std_PP_2_Turning +
              Std_PP_3_Turning +
              factor(Activity),
            data=combinedDf,
            random=~1|as.factor(Subject),
            method="REML")
method = 'REML' is not supported. Using 'qr'In lm.fit(x, y, offset = offset, singular.ok = singular.ok, ...) :
 extra argument ‘random’ will be disregarded
# anova(model)
summary(model)

Call:
lm(formula = PP_Dev ~ abs(PP_Dev_2_Straight) + abs(PP_Dev_3_Straight) + 
    abs(PP_Dev_2_Turning) + abs(PP_Dev_3_Turning) + Std_PP_2_Straight + 
    Std_PP_3_Straight + Std_PP_2_Turning + Std_PP_3_Turning + 
    factor(Activity), data = combinedDf, method = "REML", random = ~1 | 
    as.factor(Subject))

Residuals:
      Min        1Q    Median        3Q       Max 
-0.113697 -0.050326  0.003557  0.042924  0.143706 

Coefficients:
                        Estimate Std. Error t value Pr(>|t|)    
(Intercept)             0.064925   0.027247   2.383 0.019785 *  
abs(PP_Dev_2_Straight) -0.002686   0.076487  -0.035 0.972081    
abs(PP_Dev_3_Straight) -0.211257   0.143242  -1.475 0.144561    
abs(PP_Dev_2_Turning)   0.242065   0.068999   3.508 0.000776 ***
abs(PP_Dev_3_Turning)   0.080835   0.110406   0.732 0.466411    
Std_PP_2_Straight       0.397988   0.169945   2.342 0.021919 *  
Std_PP_3_Straight       0.518084   0.229902   2.253 0.027231 *  
Std_PP_2_Turning       -0.502623   0.322749  -1.557 0.123720    
Std_PP_3_Turning       -0.773228   0.289183  -2.674 0.009247 ** 
factor(Activity)M       0.090896   0.018619   4.882 6.01e-06 ***
factor(Activity)NO     -0.048262   0.019559  -2.468 0.015948 *  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.06229 on 73 degrees of freedom
Multiple R-squared:  0.5391,    Adjusted R-squared:  0.4759 
F-statistic: 8.537 on 10 and 73 DF,  p-value: 4.712e-09
plot(model)

Machine Learning

combinedDf$PP_Dev <- NULL

combinedDf$Subject <- NULL
combinedDf$Activity_NO <- ifelse(combinedDf$Activity == "NO", 1, 0)
combinedDf$Activity_C <- ifelse(combinedDf$Activity == "C", 1, 0)
combinedDf$Activity_M <- ifelse(combinedDf$Activity == "M", 1, 0)
combinedDf$Activity <- NULL

combinedDf$PP_Dev_1_Turning <-NULL
combinedDf$PP_Prior <-NULL

combinedDf$InSegment1 <- ifelse(combinedDf$Segment == 1, 1, 0)
combinedDf$InSegment2 <- ifelse(combinedDf$Segment == 2, 1, 0)
combinedDf$InSegment3 <- ifelse(combinedDf$Segment == 3, 1, 0)
combinedDf$InSegment4 <- ifelse(combinedDf$Segment == 4, 1, 0)
combinedDf$Segment <- NULL

combinedDf$Class <- ifelse(combinedDf$PP_Dev_Group == 1, T, F)
combinedDf$PP_Dev_Group <- NULL
# library(mefa)
# combinedDf <- rep(combinedDf, 10) 
n_folds <- 5
params <- param <- list(objective       = "binary:logistic", 
               booster          = "gbtree",
               eval_metric      = "auc",
               eta              = 0.1,
               max_depth        = 15,
               alpha            = 1,
               lambda           = 0,
               gamma            = 0.45,
               min_child_weight = 0.3,
               subsample        = 1,
               colsample_bytree = 1)
           
# XGBoost Model         
xgb_m <- xgb.cv(   params               = param,
                  data = as.matrix(combinedDf %>% select(-Class)) ,
                  label =  combinedDf$Class,
                  nrounds             = 100,
                  verbose             = F,
                  prediction          = T,
                  maximize            = F, # Change this value to F will help to run with more itineration
                  nfold               = n_folds,
                  metrics             = c("auc", "error"),
                  early_stopping_rounds = 50,
                  stratified            = T,
                  scale_pos_weight      = 1/2)

# xgb_m$evaluation_log[xgb_m$best_iteration,"test_auc_mean"]
xgb_m$evaluation_log[xgb_m$best_iteration,]
NA
# Prediction
combinedDf$clsPred <- round(xgb_m$pred)

computePerformanceResults <- function(sdat){
  sdat = sdat[complete.cases(sdat),]
  acc = sum(sdat[,1] == sdat[,2])/nrow(sdat)
  conf_mat = table(sdat)
  specif = conf_mat[1,1]/sum(conf_mat[,1])
  sensiv = conf_mat[2,2]/sum(conf_mat[,2])
  preci =  conf_mat[2,2]/sum(conf_mat[2,])
  npv =    conf_mat[1,1]/sum(conf_mat[1,])
  return(c(acc,specif,sensiv,preci,npv))
}

# Get average performance
performance <- computePerformanceResults(combinedDf %>% select(Class, clsPred))
acc <- performance[1]
prec <- performance[4]
recall <- performance[3]
spec <- performance[2]
npv <- performance[5]
f1 <- (2 * recall * prec) / (recall + prec)
auc <- as.numeric(xgb_m$evaluation_log[xgb_m$best_iteration, "test_auc_mean"])

print(paste("Accuracy=", round(acc, 2)))
[1] "Accuracy= 0.81"
print(paste("Precision=", round(prec, 2)))
[1] "Precision= 0.79"
print(paste("Recall=", round(recall, 2)))
[1] "Recall= 0.89"
print(paste("Specificity=", round(spec, 2)))
[1] "Specificity= 0.71"
print(paste("NPV=", round(npv, 2)))
[1] "NPV= 0.84"
print(paste("F1=", round(f1, 2)))
[1] "F1= 0.84"
print(paste("AUC=", round(auc, 2)))
[1] "AUC= 0.91"
# Importance
combinedDf$clsPred <- NULL
bst <- xgboost(   params               = param,
                  data = as.matrix(combinedDf %>% select(-Class)) ,
                  label =  combinedDf$Class,
                  nrounds             = 100,
                  verbose             = F,
                  prediction          = T,
                  maximize            = F, # Change this value to F will help to run with more itineration
                  nfold               = n_folds,
                  metrics             = c("auc", "error"),
                  early_stopping_rounds = 50,
                  stratified            = T,
                  scale_pos_weight      = 1/2)
importanceDf <- xgb.importance(colnames(combinedDf %>% select(-Class) ), model = bst)
print(importanceDf)
library(pROC)

dfROC <- pROC::roc(response = ifelse(combinedDf$Class==T, 1, 0),
               predictor = round(xgb_m$pred),
               levels=c(0, 1), direction = "<")

# it = which.max(xgb_m$evaluation_log$test_auc_mean)
# best.iter = xgb_m$evaluation_log$iter[it]
# best.iter 

plot(pROC::roc(response = ifelse(combinedDf$Class==T, 1, 0),
               predictor = round(xgb_m$pred),
               levels=c(0, 1), direction = "<"), 
     legacy.axes = TRUE,
     main="ROC Curve", 
     lwd=1.5) 

Important features

# Eleminate #5 who has an exceptional data to find a better threshold
stdPP3 <- sort(importantFeaturesDf$Std_PP_3, decreasing = T)[2:length(importantFeaturesDf$Std_PP_3)]
stdPP3Array <- matrix(stdPP3 ,nrow = 1,ncol = length(stdPP3))
  
maxStdPP3 <- sort(importantFeaturesDf$Std_PP_3, decreasing = T)[2]
PP_DEV_3_THRESHOLD <- otsu(stdPP3Array, range=c(min(stdPP3), maxStdPP3)) # Expected Threshold = 0.088
print(paste0('Threshold: ', PP_DEV_3_THRESHOLD))
[1] "Threshold: 0.0881111526518663"
importantFeaturesDf$PP_Dev_3_Group <- ifelse(importantFeaturesDf$Std_PP_3 > PP_DEV_3_THRESHOLD, 1, 0)
write.csv(importantFeaturesDf, "../outputs/importantFeatures.csv")

Plot feature importance

yAxis <- list(
  title = 'Importance',
  range=c(0.0, 1.0)
)
xAxis <- list(
  title = ''
)
importanceDf$FeatureName <- lapply(importanceDf$Feature, function(x) {
  ifelse(x=="Std_PP_3", "SD of Arousal\n in Drive M", 
         ifelse(x=="PP_Dev_2_Turning", "Arousal in Drive C\nat turning segments", 
            ifelse(x=="Activity_C", "Prior stressor\n is Cognitive", x)))
})

fig_Importance <- plot_ly(importanceDf, x = ~FeatureName, y = ~Gain, type = 'bar', name = 'Gain', width=600) %>%
  add_trace(y = ~Cover, name = 'Cover') %>% 
  add_trace(y = ~Frequency, name = 'Frequency') %>% 
  layout(yaxis = yAxis, xaxis=xAxis, barmode = 'group', title="Feature Importance") %>% 
  config(.Last.value, mathjax = 'cdn')

htmltools::tagList(fig_Importance)
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3J9CnNvdXJjZSgnLi4vc2V0dGluZ3Mvc2V0dGluZ3MuUicpCnNvdXJjZSgnY29tbW9uRnVuY3Rpb25zLlInKQpgYGAKCmBgYHtyfQpzZXQuc2VlZCg0MykKZHJpdmUxIDwtIHJlYWQuY3N2KCcuLi9kYXRhL3Byb2Nlc3NlZC9hbmFseXNpcy9UVDFfRHJpdmVfMV9QUC5jc3YnKQpkcml2ZTIgPC0gcmVhZC5jc3YoJy4uL2RhdGEvcHJvY2Vzc2VkL0FuYWx5c2lzL1RUMV9Ecml2ZV8yX1BQLmNzdicpCmRyaXZlMyA8LSByZWFkLmNzdignLi4vZGF0YS9wcm9jZXNzZWQvQW5hbHlzaXMvVFQxX0RyaXZlXzNfUFAuY3N2JykKZHJpdmU0IDwtIHJlYWQuY3N2KCcuLi9kYXRhL3Byb2Nlc3NlZC9BbmFseXNpcy9UVDFfRHJpdmVfNF9QUC5jc3YnLCBzdHJpbmdzQXNGYWN0b3JzID0gVCkKYGBgCgpgYGB7cn0KZGZTZWcgPC0gZGF0YS5mcmFtZShyZXAoMSwgbnJvdyhkcml2ZTQpKSwgcmVwKDIsIG5yb3coZHJpdmU0KSksIHJlcCgzLCBucm93KGRyaXZlNCkpLCByZXAoNCwgbnJvdyhkcml2ZTQpKSkKbmFtZXMoZGZTZWcpIDwtIGMoIlNlZzEiLCAiU2VnMiIsICJTZWczIiwgIlNlZzQiKQoKY29tYmluZWREZl9TZWcxIDwtIGNiaW5kKGRyaXZlNCwgCiAgICAgICAgICAgICAgICAgICAgZHJpdmUxJE1lYW5QUF9TZWcwLCAKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkTWVhblBQX1NlZzEsIGRyaXZlMyRNZWFuUFBfU2VnMSwgCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJE1lYW5QUF9TZWcwXzEsIGRyaXZlMyRNZWFuUFBfU2VnMF8xLAogICAgICAgICAgICAgICAgICAgIGRyaXZlMiRTdGRQUF9TZWcxLCBkcml2ZTMkU3RkUFBfU2VnMSwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkU3RkUFBfU2VnMF8xLCBkcml2ZTMkU3RkUFBfU2VnMF8xLAogICAgICAgICAgICAgICAgICAgIGRmU2VnJFNlZzEKICAgICAgICAgICAgICAgICAgKQpjb21iaW5lZERmX1NlZzIgPC0gY2JpbmQoZHJpdmU0LCAKICAgICAgICAgICAgICAgICAgICBkcml2ZTEkTWVhblBQX1NlZzAsIAogICAgICAgICAgICAgICAgICAgIGRyaXZlMiRNZWFuUFBfU2VnMiwgZHJpdmUzJE1lYW5QUF9TZWcyLCAKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkTWVhblBQX1NlZzBfMiwgZHJpdmUzJE1lYW5QUF9TZWcwXzIsCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJFN0ZFBQX1NlZzIsIGRyaXZlMyRTdGRQUF9TZWcyLAogICAgICAgICAgICAgICAgICAgIGRyaXZlMiRTdGRQUF9TZWcwXzIsIGRyaXZlMyRTdGRQUF9TZWcwXzIsCiAgICAgICAgICAgICAgICAgICAgZGZTZWckU2VnMgogICAgICAgICAgICAgICAgICApCmNvbWJpbmVkRGZfU2VnMyA8LSBjYmluZChkcml2ZTQsIAogICAgICAgICAgICAgICAgICAgIGRyaXZlMSRNZWFuUFBfU2VnMCwgCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJE1lYW5QUF9TZWczLCBkcml2ZTMkTWVhblBQX1NlZzMsIAogICAgICAgICAgICAgICAgICAgIGRyaXZlMiRNZWFuUFBfU2VnMF8zLCBkcml2ZTMkTWVhblBQX1NlZzBfMywKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkU3RkUFBfU2VnMywgZHJpdmUzJFN0ZFBQX1NlZzMsCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJFN0ZFBQX1NlZzBfMywgZHJpdmUzJFN0ZFBQX1NlZzBfMywKICAgICAgICAgICAgICAgICAgICBkZlNlZyRTZWczCiAgICAgICAgICAgICAgICAgICkKY29tYmluZWREZl9TZWc0IDwtIGNiaW5kKGRyaXZlNCwgCiAgICAgICAgICAgICAgICAgICAgZHJpdmUxJE1lYW5QUF9TZWcwLCAKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkTWVhblBQX1NlZzQsIGRyaXZlMyRNZWFuUFBfU2VnNCwgCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJE1lYW5QUF9TZWcwXzQsIGRyaXZlMyRNZWFuUFBfU2VnMF80LAogICAgICAgICAgICAgICAgICAgIGRyaXZlMiRTdGRQUF9TZWc0LCBkcml2ZTMkU3RkUFBfU2VnNCwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkU3RkUFBfU2VnMF80LCBkcml2ZTMkU3RkUFBfU2VnMF80LAogICAgICAgICAgICAgICAgICAgIGRmU2VnJFNlZzQKICAgICAgICAgICAgICAgICAgKQoKbmFtZXMoY29tYmluZWREZl9TZWcxKSA8LSBjKG5hbWVzKGRyaXZlNCksIAogICAgICAgICAgICAgICAgICAgICAgICJQUF9EZXZfMV9UdXJuaW5nIiwKICAgICAgICAgICAgICAgICAgICAgICAiUFBfRGV2XzJfU3RyYWlnaHQiLCAiUFBfRGV2XzNfU3RyYWlnaHQiLCAKICAgICAgICAgICAgICAgICAgICAgICAiUFBfRGV2XzJfVHVybmluZyIsICJQUF9EZXZfM19UdXJuaW5nIiwgCiAgICAgICAgICAgICAgICAgICAgICAgIlN0ZF9QUF8yX1N0cmFpZ2h0IiwgIlN0ZF9QUF8zX1N0cmFpZ2h0IiwgCiAgICAgICAgICAgICAgICAgICAgICAgIlN0ZF9QUF8yX1R1cm5pbmciLCAiU3RkX1BQXzNfVHVybmluZyIsIAogICAgICAgICAgICAgICAgICAgICAgICJTZWdtZW50IikKbmFtZXMoY29tYmluZWREZl9TZWcyKSA8LSBjKG5hbWVzKGRyaXZlNCksIAogICAgICAgICAgICAgICAgICAgICAgICJQUF9EZXZfMV9UdXJuaW5nIiwKICAgICAgICAgICAgICAgICAgICAgICAiUFBfRGV2XzJfU3RyYWlnaHQiLCAiUFBfRGV2XzNfU3RyYWlnaHQiLCAKICAgICAgICAgICAgICAgICAgICAgICAiUFBfRGV2XzJfVHVybmluZyIsICJQUF9EZXZfM19UdXJuaW5nIiwgCiAgICAgICAgICAgICAgICAgICAgICAgIlN0ZF9QUF8yX1N0cmFpZ2h0IiwgIlN0ZF9QUF8zX1N0cmFpZ2h0IiwgCiAgICAgICAgICAgICAgICAgICAgICAgIlN0ZF9QUF8yX1R1cm5pbmciLCAiU3RkX1BQXzNfVHVybmluZyIsIAogICAgICAgICAgICAgICAgICAgICAgICJTZWdtZW50IikKbmFtZXMoY29tYmluZWREZl9TZWczKSA8LSBjKG5hbWVzKGRyaXZlNCksIAogICAgICAgICAgICAgICAgICAgICAgICJQUF9EZXZfMV9UdXJuaW5nIiwKICAgICAgICAgICAgICAgICAgICAgICAiUFBfRGV2XzJfU3RyYWlnaHQiLCAiUFBfRGV2XzNfU3RyYWlnaHQiLCAKICAgICAgICAgICAgICAgICAgICAgICAiUFBfRGV2XzJfVHVybmluZyIsICJQUF9EZXZfM19UdXJuaW5nIiwgCiAgICAgICAgICAgICAgICAgICAgICAgIlN0ZF9QUF8yX1N0cmFpZ2h0IiwgIlN0ZF9QUF8zX1N0cmFpZ2h0IiwgCiAgICAgICAgICAgICAgICAgICAgICAgIlN0ZF9QUF8yX1R1cm5pbmciLCAiU3RkX1BQXzNfVHVybmluZyIsIAogICAgICAgICAgICAgICAgICAgICAgICJTZWdtZW50IikKbmFtZXMoY29tYmluZWREZl9TZWc0KSA8LSBjKG5hbWVzKGRyaXZlNCksIAogICAgICAgICAgICAgICAgICAgICAgICJQUF9EZXZfMV9UdXJuaW5nIiwKICAgICAgICAgICAgICAgICAgICAgICAiUFBfRGV2XzJfU3RyYWlnaHQiLCAiUFBfRGV2XzNfU3RyYWlnaHQiLCAKICAgICAgICAgICAgICAgICAgICAgICAiUFBfRGV2XzJfVHVybmluZyIsICJQUF9EZXZfM19UdXJuaW5nIiwgCiAgICAgICAgICAgICAgICAgICAgICAgIlN0ZF9QUF8yX1N0cmFpZ2h0IiwgIlN0ZF9QUF8zX1N0cmFpZ2h0IiwgCiAgICAgICAgICAgICAgICAgICAgICAgIlN0ZF9QUF8yX1R1cm5pbmciLCAiU3RkX1BQXzNfVHVybmluZyIsIAogICAgICAgICAgICAgICAgICAgICAgICJTZWdtZW50IikKCiMgY29tYmluZWREZl9TZWcxJFN1YmplY3QgPC0gcGFzdGUwKGFzLmZhY3Rvcihjb21iaW5lZERmX1NlZzEkU3ViamVjdCksICIuUzEiKQojIGNvbWJpbmVkRGZfU2VnMiRTdWJqZWN0IDwtIHBhc3RlMChhcy5mYWN0b3IoY29tYmluZWREZl9TZWcyJFN1YmplY3QpLCAiLlMyIikKIyBjb21iaW5lZERmX1NlZzMkU3ViamVjdCA8LSBwYXN0ZTAoYXMuZmFjdG9yKGNvbWJpbmVkRGZfU2VnMyRTdWJqZWN0KSwgIi5TMyIpCiMgY29tYmluZWREZl9TZWc0JFN1YmplY3QgPC0gcGFzdGUwKGFzLmZhY3Rvcihjb21iaW5lZERmX1NlZzQkU3ViamVjdCksICIuUzQiKQoKY29tYmluZWREZiA8LSByYmluZChjb21iaW5lZERmX1NlZzEsIGNvbWJpbmVkRGZfU2VnMiwgY29tYmluZWREZl9TZWczLCBjb21iaW5lZERmX1NlZzQpCgpjb21iaW5lZERmJFN1YmplY3QgPC0gcGFzdGUwKCIjIiwgc3RyX3BhZChjb21iaW5lZERmJFN1YmplY3QsIDIsIHBhZD0iMCIpKQpjb21iaW5lZERmJFNlZ21lbnQgPC0gYXMuZmFjdG9yKGNvbWJpbmVkRGYkU2VnbWVudCkKYGBgCgpgYGB7cn0KY29tYmluZWREZl9Ob1N0cmVzc29yIDwtIGNvbWJpbmVkRGZbY29tYmluZWREZiRBY3Rpdml0eSA9PSAiTk8iLF0KY29tYmluZWREZl9Db2duaXRpdmUgPC0gY29tYmluZWREZltjb21iaW5lZERmJEFjdGl2aXR5ID09ICJDIixdCmNvbWJpbmVkRGZfTW90b3JpYyA8LSBjb21iaW5lZERmW2NvbWJpbmVkRGYkQWN0aXZpdHkgPT0gIk0iLF0KCiMgY29tYmluZWREZl9Ob1N0cmVzc29yJFN1YmplY3QgPC0gYXMuZmFjdG9yKGNvbWJpbmVkRGZfTm9TdHJlc3NvciRTdWJqZWN0KQojIGNvbWJpbmVkRGZfQ29nbml0aXZlJFN1YmplY3QgPC0gYXMuZmFjdG9yKGNvbWJpbmVkRGZfQ29nbml0aXZlJFN1YmplY3QpCiMgY29tYmluZWREZl9Nb3RvcmljJFN1YmplY3QgPC0gYXMuZmFjdG9yKGNvbWJpbmVkRGZfTW90b3JpYyRTdWJqZWN0KQpgYGAKCmBgYHtyfQpDT0xPUl9OT1JNQUwgPC0gbGlzdChjb2xvcj0ncmdiKDEyMCwxMjAsMTIwKScpCkNPTE9SX0NPR05JVElWRSA8LSBsaXN0KGNvbG9yPSdyZ2IoMTU4LDIwMiwyMjUpJykKQ09MT1JfTU9UT1JJQyA8LSBsaXN0KGNvbG9yPSdyZ2IoNTgsMjAwLDIyNSknKQpDT0xPUl9GQUlMVVJFIDwtIGxpc3QoY29sb3I9J3JlZCcpCgpUSFJFU0hPTERfTUlMRCA9IDAuMDcKVEhSRVNIT0xEX0VYVFJFTUUgPSAwLjIKCk1BUktFUl9MSU5FX01JTEQgPSBsaXN0KGNvbG9yPSJibHVlIikKTUFSS0VSX0xJTkVfRVhUUkVNRSA9IGxpc3QoY29sb3I9InJlZCIpCmBgYAoKYGBge3J9CmxpYnJhcnkobmxtZSkKY29tYmluZWREZiRTdWJqZWN0ID0gYXMuZmFjdG9yKGNvbWJpbmVkRGYkU3ViamVjdCkKY29tYmluZWREZiRBY3Rpdml0eSA9IGFzLmZhY3Rvcihjb21iaW5lZERmJEFjdGl2aXR5KQpjb21iaW5lZERmJFBQX0Rldl9Hcm91cCA9IGlmZWxzZShjb21iaW5lZERmJFBQX0RldiA+IFRIUkVTSE9MRF9NSUxELCAxLCAwKQpgYGAKCmBgYHtyfQptb2RlbCA9IGxtKFBQX0RldiB+IAogICAgICAgICAgICAgIGFicyhQUF9EZXZfMl9TdHJhaWdodCkgKyAKICAgICAgICAgICAgICBhYnMoUFBfRGV2XzNfU3RyYWlnaHQpICsKICAgICAgICAgICAgICBhYnMoUFBfRGV2XzJfVHVybmluZykgKyAKICAgICAgICAgICAgICBhYnMoUFBfRGV2XzNfVHVybmluZykgKyAKICAgICAgICAgICAgICBTdGRfUFBfMl9TdHJhaWdodCArIAogICAgICAgICAgICAgIFN0ZF9QUF8zX1N0cmFpZ2h0ICsgCiAgICAgICAgICAgICAgU3RkX1BQXzJfVHVybmluZyArCiAgICAgICAgICAgICAgU3RkX1BQXzNfVHVybmluZyArCiAgICAgICAgICAgICAgZmFjdG9yKEFjdGl2aXR5KSwKICAgICAgICAgICAgZGF0YT1jb21iaW5lZERmLAogICAgICAgICAgICByYW5kb209fjF8YXMuZmFjdG9yKFN1YmplY3QpLAogICAgICAgICAgICBtZXRob2Q9IlJFTUwiKQoKIyBhbm92YShtb2RlbCkKc3VtbWFyeShtb2RlbCkKcGxvdChtb2RlbCkKYGBgCgojIyBNYWNoaW5lIExlYXJuaW5nCgpgYGB7cn0KY29tYmluZWREZiRQUF9EZXYgPC0gTlVMTAoKY29tYmluZWREZiRTdWJqZWN0IDwtIE5VTEwKY29tYmluZWREZiRBY3Rpdml0eV9OTyA8LSBpZmVsc2UoY29tYmluZWREZiRBY3Rpdml0eSA9PSAiTk8iLCAxLCAwKQpjb21iaW5lZERmJEFjdGl2aXR5X0MgPC0gaWZlbHNlKGNvbWJpbmVkRGYkQWN0aXZpdHkgPT0gIkMiLCAxLCAwKQpjb21iaW5lZERmJEFjdGl2aXR5X00gPC0gaWZlbHNlKGNvbWJpbmVkRGYkQWN0aXZpdHkgPT0gIk0iLCAxLCAwKQpjb21iaW5lZERmJEFjdGl2aXR5IDwtIE5VTEwKCmNvbWJpbmVkRGYkUFBfRGV2XzFfVHVybmluZyA8LU5VTEwKY29tYmluZWREZiRQUF9QcmlvciA8LU5VTEwKCmNvbWJpbmVkRGYkSW5TZWdtZW50MSA8LSBpZmVsc2UoY29tYmluZWREZiRTZWdtZW50ID09IDEsIDEsIDApCmNvbWJpbmVkRGYkSW5TZWdtZW50MiA8LSBpZmVsc2UoY29tYmluZWREZiRTZWdtZW50ID09IDIsIDEsIDApCmNvbWJpbmVkRGYkSW5TZWdtZW50MyA8LSBpZmVsc2UoY29tYmluZWREZiRTZWdtZW50ID09IDMsIDEsIDApCmNvbWJpbmVkRGYkSW5TZWdtZW50NCA8LSBpZmVsc2UoY29tYmluZWREZiRTZWdtZW50ID09IDQsIDEsIDApCmNvbWJpbmVkRGYkU2VnbWVudCA8LSBOVUxMCgpjb21iaW5lZERmJENsYXNzIDwtIGlmZWxzZShjb21iaW5lZERmJFBQX0Rldl9Hcm91cCA9PSAxLCBULCBGKQpjb21iaW5lZERmJFBQX0Rldl9Hcm91cCA8LSBOVUxMCmBgYAoKYGBge3J9CiMgbGlicmFyeShtZWZhKQojIGNvbWJpbmVkRGYgPC0gcmVwKGNvbWJpbmVkRGYsIDEwKSAKYGBgCgpgYGB7cn0Kbl9mb2xkcyA8LSA1CnBhcmFtcyA8LSBwYXJhbSA8LSBsaXN0KG9iamVjdGl2ZSAgICAgICA9ICJiaW5hcnk6bG9naXN0aWMiLCAKICAgICAgICAgICAgICAgYm9vc3RlciAgICAgICAgICA9ICJnYnRyZWUiLAogICAgICAgICAgICAgICBldmFsX21ldHJpYyAgICAgID0gImF1YyIsCiAgICAgICAgICAgICAgIGV0YSAgICAgICAgICAgICAgPSAwLjEsCiAgICAgICAgICAgICAgIG1heF9kZXB0aCAgICAgICAgPSAxNSwKICAgICAgICAgICAgICAgYWxwaGEgICAgICAgICAgICA9IDEsCiAgICAgICAgICAgICAgIGxhbWJkYSAgICAgICAgICAgPSAwLAogICAgICAgICAgICAgICBnYW1tYSAgICAgICAgICAgID0gMC40NSwKICAgICAgICAgICAgICAgbWluX2NoaWxkX3dlaWdodCA9IDAuMywKICAgICAgICAgICAgICAgc3Vic2FtcGxlICAgICAgICA9IDEsCiAgICAgICAgICAgICAgIGNvbHNhbXBsZV9ieXRyZWUgPSAxKQogICAgICAgICAgIAojIFhHQm9vc3QgTW9kZWwgICAgICAgICAKeGdiX20gPC0geGdiLmN2KCAgIHBhcmFtcyAgICAgICAgICAgICAgID0gcGFyYW0sCiAgICAgICAgICAgICAgICAgIGRhdGEgPSBhcy5tYXRyaXgoY29tYmluZWREZiAlPiUgc2VsZWN0KC1DbGFzcykpICwKICAgICAgICAgICAgICAgICAgbGFiZWwgPSAgY29tYmluZWREZiRDbGFzcywKICAgICAgICAgICAgICAgICAgbnJvdW5kcyAgICAgICAgICAgICA9IDEwMCwKICAgICAgICAgICAgICAgICAgdmVyYm9zZSAgICAgICAgICAgICA9IEYsCiAgICAgICAgICAgICAgICAgIHByZWRpY3Rpb24gICAgICAgICAgPSBULAogICAgICAgICAgICAgICAgICBtYXhpbWl6ZSAgICAgICAgICAgID0gRiwgIyBDaGFuZ2UgdGhpcyB2YWx1ZSB0byBGIHdpbGwgaGVscCB0byBydW4gd2l0aCBtb3JlIGl0aW5lcmF0aW9uCiAgICAgICAgICAgICAgICAgIG5mb2xkICAgICAgICAgICAgICAgPSBuX2ZvbGRzLAogICAgICAgICAgICAgICAgICBtZXRyaWNzICAgICAgICAgICAgID0gYygiYXVjIiwgImVycm9yIiksCiAgICAgICAgICAgICAgICAgIGVhcmx5X3N0b3BwaW5nX3JvdW5kcyA9IDUwLAogICAgICAgICAgICAgICAgICBzdHJhdGlmaWVkICAgICAgICAgICAgPSBULAogICAgICAgICAgICAgICAgICBzY2FsZV9wb3Nfd2VpZ2h0ICAgICAgPSAxLzIpCgojIHhnYl9tJGV2YWx1YXRpb25fbG9nW3hnYl9tJGJlc3RfaXRlcmF0aW9uLCJ0ZXN0X2F1Y19tZWFuIl0KeGdiX20kZXZhbHVhdGlvbl9sb2dbeGdiX20kYmVzdF9pdGVyYXRpb24sXQoKYGBgCgpgYGB7cn0KIyBQcmVkaWN0aW9uCmNvbWJpbmVkRGYkY2xzUHJlZCA8LSByb3VuZCh4Z2JfbSRwcmVkKQoKY29tcHV0ZVBlcmZvcm1hbmNlUmVzdWx0cyA8LSBmdW5jdGlvbihzZGF0KXsKICBzZGF0ID0gc2RhdFtjb21wbGV0ZS5jYXNlcyhzZGF0KSxdCiAgYWNjID0gc3VtKHNkYXRbLDFdID09IHNkYXRbLDJdKS9ucm93KHNkYXQpCiAgY29uZl9tYXQgPSB0YWJsZShzZGF0KQogIHNwZWNpZiA9IGNvbmZfbWF0WzEsMV0vc3VtKGNvbmZfbWF0WywxXSkKICBzZW5zaXYgPSBjb25mX21hdFsyLDJdL3N1bShjb25mX21hdFssMl0pCiAgcHJlY2kgPSAgY29uZl9tYXRbMiwyXS9zdW0oY29uZl9tYXRbMixdKQogIG5wdiA9ICAgIGNvbmZfbWF0WzEsMV0vc3VtKGNvbmZfbWF0WzEsXSkKICByZXR1cm4oYyhhY2Msc3BlY2lmLHNlbnNpdixwcmVjaSxucHYpKQp9CgojIEdldCBhdmVyYWdlIHBlcmZvcm1hbmNlCnBlcmZvcm1hbmNlIDwtIGNvbXB1dGVQZXJmb3JtYW5jZVJlc3VsdHMoY29tYmluZWREZiAlPiUgc2VsZWN0KENsYXNzLCBjbHNQcmVkKSkKYWNjIDwtIHBlcmZvcm1hbmNlWzFdCnByZWMgPC0gcGVyZm9ybWFuY2VbNF0KcmVjYWxsIDwtIHBlcmZvcm1hbmNlWzNdCnNwZWMgPC0gcGVyZm9ybWFuY2VbMl0KbnB2IDwtIHBlcmZvcm1hbmNlWzVdCmYxIDwtICgyICogcmVjYWxsICogcHJlYykgLyAocmVjYWxsICsgcHJlYykKYXVjIDwtIGFzLm51bWVyaWMoeGdiX20kZXZhbHVhdGlvbl9sb2dbeGdiX20kYmVzdF9pdGVyYXRpb24sICJ0ZXN0X2F1Y19tZWFuIl0pCgpwcmludChwYXN0ZSgiQWNjdXJhY3k9Iiwgcm91bmQoYWNjLCAyKSkpCnByaW50KHBhc3RlKCJQcmVjaXNpb249Iiwgcm91bmQocHJlYywgMikpKQpwcmludChwYXN0ZSgiUmVjYWxsPSIsIHJvdW5kKHJlY2FsbCwgMikpKQpwcmludChwYXN0ZSgiU3BlY2lmaWNpdHk9Iiwgcm91bmQoc3BlYywgMikpKQpwcmludChwYXN0ZSgiTlBWPSIsIHJvdW5kKG5wdiwgMikpKQpwcmludChwYXN0ZSgiRjE9Iiwgcm91bmQoZjEsIDIpKSkKcHJpbnQocGFzdGUoIkFVQz0iLCByb3VuZChhdWMsIDIpKSkKYGBgCgpgYGB7cn0KIyBJbXBvcnRhbmNlCmNvbWJpbmVkRGYkY2xzUHJlZCA8LSBOVUxMCmJzdCA8LSB4Z2Jvb3N0KCAgIHBhcmFtcyAgICAgICAgICAgICAgID0gcGFyYW0sCiAgICAgICAgICAgICAgICAgIGRhdGEgPSBhcy5tYXRyaXgoY29tYmluZWREZiAlPiUgc2VsZWN0KC1DbGFzcykpICwKICAgICAgICAgICAgICAgICAgbGFiZWwgPSAgY29tYmluZWREZiRDbGFzcywKICAgICAgICAgICAgICAgICAgbnJvdW5kcyAgICAgICAgICAgICA9IDEwMCwKICAgICAgICAgICAgICAgICAgdmVyYm9zZSAgICAgICAgICAgICA9IEYsCiAgICAgICAgICAgICAgICAgIHByZWRpY3Rpb24gICAgICAgICAgPSBULAogICAgICAgICAgICAgICAgICBtYXhpbWl6ZSAgICAgICAgICAgID0gRiwgIyBDaGFuZ2UgdGhpcyB2YWx1ZSB0byBGIHdpbGwgaGVscCB0byBydW4gd2l0aCBtb3JlIGl0aW5lcmF0aW9uCiAgICAgICAgICAgICAgICAgIG5mb2xkICAgICAgICAgICAgICAgPSBuX2ZvbGRzLAogICAgICAgICAgICAgICAgICBtZXRyaWNzICAgICAgICAgICAgID0gYygiYXVjIiwgImVycm9yIiksCiAgICAgICAgICAgICAgICAgIGVhcmx5X3N0b3BwaW5nX3JvdW5kcyA9IDUwLAogICAgICAgICAgICAgICAgICBzdHJhdGlmaWVkICAgICAgICAgICAgPSBULAogICAgICAgICAgICAgICAgICBzY2FsZV9wb3Nfd2VpZ2h0ICAgICAgPSAxLzIpCmltcG9ydGFuY2VEZiA8LSB4Z2IuaW1wb3J0YW5jZShjb2xuYW1lcyhjb21iaW5lZERmICU+JSBzZWxlY3QoLUNsYXNzKSApLCBtb2RlbCA9IGJzdCkKcHJpbnQoaW1wb3J0YW5jZURmKQpgYGAKCmBgYHtyfQpsaWJyYXJ5KHBST0MpCgpkZlJPQyA8LSBwUk9DOjpyb2MocmVzcG9uc2UgPSBpZmVsc2UoY29tYmluZWREZiRDbGFzcz09VCwgMSwgMCksCiAgICAgICAgICAgICAgIHByZWRpY3RvciA9IHJvdW5kKHhnYl9tJHByZWQpLAogICAgICAgICAgICAgICBsZXZlbHM9YygwLCAxKSwgZGlyZWN0aW9uID0gIjwiKQoKIyBpdCA9IHdoaWNoLm1heCh4Z2JfbSRldmFsdWF0aW9uX2xvZyR0ZXN0X2F1Y19tZWFuKQojIGJlc3QuaXRlciA9IHhnYl9tJGV2YWx1YXRpb25fbG9nJGl0ZXJbaXRdCiMgYmVzdC5pdGVyIAoKcGxvdChwUk9DOjpyb2MocmVzcG9uc2UgPSBpZmVsc2UoY29tYmluZWREZiRDbGFzcz09VCwgMSwgMCksCiAgICAgICAgICAgICAgIHByZWRpY3RvciA9IHJvdW5kKHhnYl9tJHByZWQpLAogICAgICAgICAgICAgICBsZXZlbHM9YygwLCAxKSwgZGlyZWN0aW9uID0gIjwiKSwgCiAgICAgbGVnYWN5LmF4ZXMgPSBUUlVFLAogICAgIG1haW49IlJPQyBDdXJ2ZSIsIAogICAgIGx3ZD0xLjUpIApgYGAKCiMgSW1wb3J0YW50IGZlYXR1cmVzCmBgYHtyfQojIEVsZW1pbmF0ZSAjNSB3aG8gaGFzIGFuIGV4Y2VwdGlvbmFsIGRhdGEgdG8gZmluZCBhIGJldHRlciB0aHJlc2hvbGQKc3RkUFAzIDwtIHNvcnQoaW1wb3J0YW50RmVhdHVyZXNEZiRTdGRfUFBfMywgZGVjcmVhc2luZyA9IFQpWzI6bGVuZ3RoKGltcG9ydGFudEZlYXR1cmVzRGYkU3RkX1BQXzMpXQpzdGRQUDNBcnJheSA8LSBtYXRyaXgoc3RkUFAzICxucm93ID0gMSxuY29sID0gbGVuZ3RoKHN0ZFBQMykpCiAgCm1heFN0ZFBQMyA8LSBzb3J0KGltcG9ydGFudEZlYXR1cmVzRGYkU3RkX1BQXzMsIGRlY3JlYXNpbmcgPSBUKVsyXQpQUF9ERVZfM19USFJFU0hPTEQgPC0gb3RzdShzdGRQUDNBcnJheSwgcmFuZ2U9YyhtaW4oc3RkUFAzKSwgbWF4U3RkUFAzKSkgIyBFeHBlY3RlZCBUaHJlc2hvbGQgPSAwLjA4OApwcmludChwYXN0ZTAoJ1RocmVzaG9sZDogJywgUFBfREVWXzNfVEhSRVNIT0xEKSkKCmltcG9ydGFudEZlYXR1cmVzRGYkUFBfRGV2XzNfR3JvdXAgPC0gaWZlbHNlKGltcG9ydGFudEZlYXR1cmVzRGYkU3RkX1BQXzMgPiBQUF9ERVZfM19USFJFU0hPTEQsIDEsIDApCndyaXRlLmNzdihpbXBvcnRhbnRGZWF0dXJlc0RmLCAiLi4vb3V0cHV0cy9pbXBvcnRhbnRGZWF0dXJlcy5jc3YiKQpgYGAKCgojIyMgUGxvdCBmZWF0dXJlIGltcG9ydGFuY2UKYGBge3J9CnlBeGlzIDwtIGxpc3QoCiAgdGl0bGUgPSAnSW1wb3J0YW5jZScsCiAgcmFuZ2U9YygwLjAsIDEuMCkKKQp4QXhpcyA8LSBsaXN0KAogIHRpdGxlID0gJycKKQppbXBvcnRhbmNlRGYkRmVhdHVyZU5hbWUgPC0gbGFwcGx5KGltcG9ydGFuY2VEZiRGZWF0dXJlLCBmdW5jdGlvbih4KSB7CiAgaWZlbHNlKHg9PSJTdGRfUFBfMyIsICJTRCBvZiBBcm91c2FsXG4gaW4gRHJpdmUgTSIsIAogICAgICAgICBpZmVsc2UoeD09IlBQX0Rldl8yX1R1cm5pbmciLCAiQXJvdXNhbCBpbiBEcml2ZSBDXG5hdCB0dXJuaW5nIHNlZ21lbnRzIiwgCiAgICAgICAgICAgIGlmZWxzZSh4PT0iQWN0aXZpdHlfQyIsICJQcmlvciBzdHJlc3NvclxuIGlzIENvZ25pdGl2ZSIsIHgpKSkKfSkKCmZpZ19JbXBvcnRhbmNlIDwtIHBsb3RfbHkoaW1wb3J0YW5jZURmLCB4ID0gfkZlYXR1cmVOYW1lLCB5ID0gfkdhaW4sIHR5cGUgPSAnYmFyJywgbmFtZSA9ICdHYWluJywgd2lkdGg9NjAwKSAlPiUKICBhZGRfdHJhY2UoeSA9IH5Db3ZlciwgbmFtZSA9ICdDb3ZlcicpICU+JSAKICBhZGRfdHJhY2UoeSA9IH5GcmVxdWVuY3ksIG5hbWUgPSAnRnJlcXVlbmN5JykgJT4lIAogIGxheW91dCh5YXhpcyA9IHlBeGlzLCB4YXhpcz14QXhpcywgYmFybW9kZSA9ICdncm91cCcsIHRpdGxlPSJGZWF0dXJlIEltcG9ydGFuY2UiKSAlPiUgCiAgY29uZmlnKC5MYXN0LnZhbHVlLCBtYXRoamF4ID0gJ2NkbicpCgpodG1sdG9vbHM6OnRhZ0xpc3QoZmlnX0ltcG9ydGFuY2UpCmBgYAoKCgoK